﻿#include "discrete_face_cone.hxx"
#include "discrete_face_loop.hxx"
#include "discrete_face_utils.hxx"
#include "idx_mesh_utils.hxx"
void cone_faceter::init() {
    // sphere is only closed on v , not on u
    // mainly [-pi/2,pi/2]*[-pi, pi)
    // 获取锥面
    localCone = (cone*)&f->geometry()->equation_for_update();
    SPAinterval u_interval = f->geometry()->equation().param_range_u();
    SPAinterval v_interval = f->geometry()->equation().param_range_v();
    // 根据u参数的范围
    switch (u_interval.type()) {
    case interval_finite:  // interval为finite时
        // u的左边界是起始点
        u_le = u_interval.start_pt();
        // u的右边界是结束点
        u_ri = u_interval.end_pt();
        break;
    case interval_finite_below:  // interval类型是finite_below时
        // u的左边界是起始点
        u_le = u_interval.start_pt();
        // u的右边界取左边界的负数
        u_ri = -u_le;
        // 如果u_le被映射到锥面是一个奇异点，需要指出
        if (localCone->singular_u(u_le)) {
            singular_ule = true;
        }
        break;
    case interval_finite_above:  // interval类型是finite_abow时
        // u的右边界时结束点
        u_ri = u_interval.end_pt();
        // u的左边界取右边界的负值
        u_le = -u_ri;
        // 如果u_ri被映射到锥面是一个奇异点，需要指出
        if (localCone->singular_u(u_ri)) {
            singular_uri = true;
        }
        break;
    case interval_infinite:
    case interval_unknown:
        // 暂时通过改变系数的方案解决
        u_ri = localCone->u_param_scale;
        u_le = -u_ri;
        // is_infinite_u = true;
    }
    // 由于锥面在参数v上存在周期性，无需对其进行范围化约束
    // v的左边界是起始点
    v_le = v_interval.start_pt();
    // v的右边界是结束点
    v_ri = v_interval.end_pt();
    // 默认u,v的容差
    u_tolerance = 1e15;
    v_tolerance = 1e15;
    if (f->geometry()->equation().closed_u()) u_tolerance = localCone->param_range_u().length() / 2;  // 判断跨边界所用值
    if (f->geometry()->equation().closed_v()) v_tolerance = localCone->param_range_v().length() / 2;

    le_low.x = u_le;  // 左下角点
    le_low.y = v_le;
    ri_high.x = u_ri;
    ri_high.y = v_ri;
    if (localCone->cosine_angle < 0 && f->sense() == FORWARD || localCone->cosine_angle > 0 && f->sense() == REVERSED) normalR = true;
}

void cone_faceter::attachMesh() {
    double expansion_cofficient = 1e-3;
    int point_cnt = 0;
    // check 若为退化face则直接return

    for (int i = 0; i < points.size(); i++) {
        points[i].x *= expansion_cofficient;
    }
    REVBIT r = f->sense();

    CDT::Triangulation<double>* pcdt = nullptr;  // CDT进行三角剖分

    if (pcdt) ACIS_DELETE pcdt;
    pcdt = ACIS_NEW CDT::Triangulation<double>;
    CDT::RemoveDuplicatesAndRemapEdges(points, edges);

    for (int i = 0; i < points.size(); i++) {
        points[i].x /= expansion_cofficient;
    }

    for (int i = 0; i < points.size(); i++) {
        points[i].x *= expansion_cofficient;
    }
    pcdt->insertVertices(points);
    pcdt->insertEdges(edges);
    pcdt->eraseOuterTrianglesAndHoles();

    CDT::TriangleVec triangles = pcdt->triangles;
    std::vector<CDT::V2d<double>> vertice = pcdt->vertices;

    std::vector<UV_VERTEX> uv_vertices;
    for (int i = 0; i < vertice.size(); i++) {
        CDT::V2d<double> pp = vertice[i];
        SPApar_pos param(pp.x / expansion_cofficient, pp.y);
        SPAposition pos = f->geometry()->equation().eval_position(param);
        SPAunit_vector normal = f->geometry()->equation().eval_outdir(param);
        if (r) normal = -normal;
        uv_vertices.emplace_back(pos, normal, param);
    }
    for (int i = 0; i < triangles.size(); i++) {
        int p1 = triangles[i].vertices[0];
        int p2 = triangles[i].vertices[1];
        int p3 = triangles[i].vertices[2];
        if (!localCone->_IsCylinder) {
            SPAposition apex = localCone->get_apex();
            double sign = 1.0;
            if (singular_uri) sign *= -1.0;
            if (uv_vertices[p1].position == apex) {
                double tmp_u = uv_vertices[p1].uv.u;
                double tmp_v1 = uv_vertices[p2].uv.v;
                double tmp_v2 = uv_vertices[p3].uv.v;
                SPApar_pos tmp_p(tmp_u + sign * SPAresabs, (tmp_v1 + tmp_v2) / 2);
                SPAunit_vector tmp_n = f->geometry()->equation().eval_normal(tmp_p);
                if (f->sense()) tmp_n = -tmp_n;
                uv_vertices[p1].normal = tmp_n;
            }
            else if (uv_vertices[p2].position == apex) {
                double tmp_u = uv_vertices[p2].uv.u;
                double tmp_v1 = uv_vertices[p1].uv.v;
                double tmp_v2 = uv_vertices[p3].uv.v;
                SPApar_pos tmp_p(tmp_u + sign * SPAresabs, (tmp_v1 + tmp_v2) / 2);
                SPAunit_vector tmp_n = f->geometry()->equation().eval_normal(tmp_p);
                if (f->sense()) tmp_n = -tmp_n;
                uv_vertices[p2].normal = tmp_n;
            }
            else if (uv_vertices[p3].position == apex) {
                double tmp_u = uv_vertices[p3].uv.u;
                double tmp_v1 = uv_vertices[p1].uv.v;
                double tmp_v2 = uv_vertices[p2].uv.v;
                SPApar_pos tmp_p(tmp_u + sign * SPAresabs, (tmp_v1 + tmp_v2) / 2);
                SPAunit_vector tmp_n = f->geometry()->equation().eval_normal(tmp_p);
                if (f->sense()) tmp_n = -tmp_n;
                uv_vertices[p3].normal = tmp_n;
            }
        }
    }
    NewIndexedMesh(f, uv_vertices, triangles);
}

outcome cone_faceter::facet() {
    init();

    auto generator = [&](SPApar_pos begin, SPApar_pos end) {
        // 获取未进行奇点处理的loop的点的数量，来确定奇点处理的分段数。
        // 这里是再处理了一次loop，感觉会对效率产生一定影响，后续可以把这一段修改一下，看看能否直接获取初始loop中的
        auto tmp_loop_processor = LoopProcessor(f);
        tmp_loop_processor.Execute();
        int cnt = 0;
        std::vector<SPApar_pos> tmp;
        cnt = tmp_loop_processor.points.size();
        assert(cnt != 0);
        /////////////////////////////////////////////////////////////////////////
        // 对奇点进行处理，增加参数域上奇点的点，为了奇点法向量？水密性?
        double step = abs(begin.v - end.v) / cnt;
        if (is_zero_mch(begin.v - end.v)) return tmp;
        if (singular_ule) {
            for (double v = begin.v - step; v > end.v; v -= step) {
                tmp.emplace_back(u_ri, v);
            }
        }
        else if (singular_uri) {
            for (double v = begin.v + step; v < end.v; v += step) {
                tmp.emplace_back(u_ri, v);
            }
        }
        return tmp;
        };

    auto loop_processor = LoopProcessor(f);
    loop_processor.RegisterGenerator(generator);
    loop_processor.RegisterSingularityGenerator(generator);
    loop_processor.Execute();
    for (auto x : loop_processor.points) {
        points.emplace_back(x.u, x.v);
    }
    for (int loop_idx = 0; loop_idx < loop_processor.loops_indexs.size(); loop_idx++) {
        auto& point_indexs = loop_processor.loops_indexs[loop_idx];
        int point_indexs_size = point_indexs.size();
        if (point_indexs_size < 2) continue;
        for (int i = 1; i < point_indexs_size; i++) {
            edges.emplace_back(point_indexs[i], point_indexs[i - 1]);
        }
        edges.emplace_back(point_indexs.front(), point_indexs.back());
    }

    attachMesh();
    return outcome();
}

outcome facet_face_cone(FACE* f, double nt, double st) {
    // api_split_periodic_faces(f);
    cone_faceter faceter(f, nt, st);
    return faceter.facet();
}
